import re,subprocess
import logging
# 执行svn命令
def exe_svn_command(command):
    try:
        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                            shell=True)
        stdout, stderr = p.communicate()
        stdout = stdout.decode("gbk")
        stderr = stderr.decode("gbk")
        if stderr != "":
            print("stderr:\n",stderr)
            logging.warning(stderr)
        return stdout   
    except subprocess.CalledProcessError as e:
        print(f'Subprocess failed with return code {e.returncode}')
    except FileNotFoundError:
        print('Command not found')
# 获取本地文件夹对应的 svnURl 
def get_svn_url_by_path(work_path):
    smdStr = f"svn info \"{work_path}\""
    text = exe_svn_command(smdStr)
    match = re.search(r'URL: (svn://[^\n]*)', text)
    if not match:
        print(f'未识别到svn_url:请确保{work_path}是svn的工作副本!')
        return ''
    return match.group(1)
# 获取本地文件夹对应的 version
def get_svn_version_by_path(work_path):
    smdStr = f"svn info \"{work_path}\""
    text = exe_svn_command(smdStr)
    match = re.search(r'Revision:\s*([0-9|\.]+)', text)
    if not match:
        print(f'未识别到version:请确保{work_path}是svn的工作副本!')
        return ''
    return match.group(1)
# revert 撤销所有未提交的本地修改
def revert(work_path):
    smdStr = f"svn revert -R \"{work_path}\""
    exe_svn_command(smdStr)
# cleanup 确保工作副本处于一致状态
def cleanup(work_path):
    smdStr = f"svn cleanup \"{work_path}\""
    exe_svn_command(smdStr)
# update 将工作副本更新到最新版本
def update(work_path):
    smdStr = f"svn update \"{work_path}\""
    exe_svn_command(smdStr)
# 获取文件的guid
def get_guid(filepath):
    text = ''
    with open(filepath, mode='r') as file:
        text = file.read()
    match = re.search(r'guid:\s*(\w+)', text)
    if not match:
        #logging.warning(".meta 文件：%s 解析 GUID 失败", path)
        print(f'.meta 文件：{filepath} 解析 GUID 失败')
        return ''
    return match.group(1)
# 迭代更新，直到最新版本
def get_project_mates_to_up_to_date(work_path,version,mate_dict):
    diff_mate_list=check_version(work_path,version)
    if len(diff_mate_list)==0:
        return mate_dict
    # 当前工作副本和服务器文件有差异，更新version
    version=get_svn_url_by_path(work_path)
    for diff_mate in diff_mate_list:
        # 如果变更操作是D，即删除，从字典中删除该文件的相关信息
        if diff_mate['status']=='D' and diff_mate['path'] in mate_dict:
            del mate_dict[diff_mate['path']] 
        # 如果是其他操作，就重新记录该文件到字典中
        elif diff_mate['status']!='D':
            guid=get_guid(f"{work_path}\\{diff_mate['path']}")
            mate_dict[diff_mate['path']]=guid
    # 迭代，直到 当前工作副本和服务器文件无差异
    return get_project_mates_to_up_to_date(work_path,version,mate_dict)
# 获取项目的mate文件信息
def get_project_mates(work_path):
    mate_dict = {}
    svn_assets_url = get_svn_url_by_path(work_path)
    if svn_assets_url !='':
        # 撤销
        revert(work_path)
        # 清理
        cleanup(work_path)
        # 更新
        update(work_path)
        # 记录当前版本
        version=get_svn_version_by_path(work_path)
        cmdStr = f"svn list -R {svn_assets_url} --non-interactive | find \".meta\" "
        metafile_list = exe_svn_command(cmdStr).splitlines()
        for file in metafile_list:
            if "~/" in file:
                continue
            guid=get_guid(f"{work_path}\\{file}")
            mate_dict[file]=guid
        # 多次更新，直到最新版本
        get_project_mates_to_up_to_date(work_path,version,mate_dict)
    return mate_dict
# 检查当前工作副本与新版本的差异
def check_version(work_path,version):
    diff_list=[]
    smdStr = f"cd {work_path} && svn update"
    text = exe_svn_command(smdStr)
    match=re.search(r'revision[\s]*([^\n]*)\.',text)
    if not match:
        print(f'检查失败:请确保{work_path}是svn的工作副本!')
        return diff_list
    if match.group(1)==version:
        print(f"当前已是最新版本！")
        return diff_list
    update_result_list=text.splitlines()
    for line in update_result_list:
        match=re.search(r'([A-Z])[\s]*([^\n]*.meta)',line)
        if not match or "~/" in match.group(2):
            continue
        diff_list.append({"status":match.group(1),"path":match.group(2)})
    return diff_list
work_path=r"D:\work\svn\SvnToolTest"
mate_dict=get_project_mates(work_path)
for i in mate_dict:
    print(f"{i}-{mate_dict[i]}")
print(f"mate_dict=【{len(mate_dict)}】")